jetcrab\bytecode\expressions/
assignment.rs1use crate::ast::Node;
2use crate::vm::instructions::Instruction;
3use crate::vm::types::{CodeAddress, LocalIndex};
4
5pub trait AssignmentGenerator {
6 fn generate_assignment_expression(&mut self, node: &Node);
7 fn generate_conditional_expression(&mut self, node: &Node);
8 fn generate_call_expression(&mut self, node: &Node);
9 fn generate_new_expression(&mut self, node: &Node);
10 fn generate_member_expression(&mut self, node: &Node);
11}
12
13pub trait AssignmentCore {
14 fn instructions(&mut self) -> &mut Vec<Instruction>;
15 fn visit_node(&mut self, node: &Node);
16}
17
18impl<T> AssignmentGenerator for T
19where
20 T: AssignmentCore + crate::bytecode::scope::constants::ConstantCore + crate::bytecode::scope::local_vars::ScopeManager,
21{
22 fn generate_assignment_expression(&mut self, node: &Node) {
23 if let Node::AssignmentExpression(expr) = node {
24 match expr.operator.as_str() {
25 "=" => {
26 match &*expr.left {
28 Node::Identifier(ident) => {
29 self.visit_node(&expr.right);
31 let local_idx = self.get_or_create_local(ident);
32 self.instructions().push(Instruction::StoreLocal(local_idx));
33 }
34 Node::MemberExpression(member) => {
35 self.visit_node(&member.object); match &*member.property {
40 Node::Identifier(name) if !member.computed => {
41 let constant_id = <Self as crate::bytecode::scope::constants::ConstantManager>::add_constant(self, name.clone());
43 self.instructions().push(Instruction::PushConst(constant_id));
44 }
45 _ => {
46 self.visit_node(&member.property);
48 }
49 }
50
51 self.visit_node(&expr.right); self.instructions().push(Instruction::SetPropertyAssign);
53 }
54 _ => {
55 self.visit_node(&expr.right);
57 self.instructions().push(Instruction::StoreLocal(LocalIndex::new(0)));
58 }
59 }
60 }
61 "+=" => {
62 if let Node::Identifier(ident) = &*expr.left {
64 let local_idx = self.get_or_create_local(ident);
65
66 self.instructions().push(Instruction::LoadLocal(local_idx));
68
69 self.visit_node(&expr.right);
71
72 self.instructions().push(Instruction::Add);
74
75 self.instructions().push(Instruction::StoreLocal(local_idx));
77 } else {
78 self.instructions().push(Instruction::PushUndefined);
79 }
80 }
81 "-=" => {
82 if let Node::Identifier(ident) = &*expr.left {
84 let local_idx = self.get_or_create_local(ident);
85
86 self.instructions().push(Instruction::LoadLocal(local_idx));
88
89 self.visit_node(&expr.right);
91
92 self.instructions().push(Instruction::Sub);
94
95 self.instructions().push(Instruction::StoreLocal(local_idx));
97 } else {
98 self.instructions().push(Instruction::PushUndefined);
99 }
100 }
101 "*=" => {
102 if let Node::Identifier(ident) = &*expr.left {
104 let local_idx = self.get_or_create_local(ident);
105
106 self.instructions().push(Instruction::LoadLocal(local_idx));
108
109 self.visit_node(&expr.right);
111
112 self.instructions().push(Instruction::Mul);
114
115 self.instructions().push(Instruction::StoreLocal(local_idx));
117 } else {
118 self.instructions().push(Instruction::PushUndefined);
119 }
120 }
121 "/=" => {
122 if let Node::Identifier(ident) = &*expr.left {
124 let local_idx = self.get_or_create_local(ident);
125
126 self.instructions().push(Instruction::LoadLocal(local_idx));
128
129 self.visit_node(&expr.right);
131
132 self.instructions().push(Instruction::Div);
134
135 self.instructions().push(Instruction::StoreLocal(local_idx));
137 } else {
138 self.instructions().push(Instruction::PushUndefined);
139 }
140 }
141 _ => {
142 self.visit_node(&expr.right);
144
145 if let Node::Identifier(ident) = &*expr.left {
146 let local_idx = self.get_or_create_local(ident);
147 self.instructions().push(Instruction::StoreLocal(local_idx));
148 } else {
149 self.instructions().push(Instruction::StoreLocal(LocalIndex::new(0)));
150 }
151 }
152 }
153 }
154 }
155
156 fn generate_conditional_expression(&mut self, node: &Node) {
157 if let Node::ConditionalExpression(expr) = node {
158 self.visit_node(&expr.test);
159
160 let jump_to_alternate = self.instructions().len();
161 self.instructions()
162 .push(Instruction::JumpIfFalse(CodeAddress::new(0)));
163
164 self.visit_node(&expr.consequent);
165
166 let jump_to_end = self.instructions().len();
167 self.instructions()
168 .push(Instruction::Jump(CodeAddress::new(0)));
169
170 let alternate_start = self.instructions().len();
171 self.instructions()[jump_to_alternate] =
172 Instruction::JumpIfFalse(CodeAddress::new(alternate_start));
173
174 self.visit_node(&expr.alternate);
175
176 let end_pos = self.instructions().len();
177 self.instructions()[jump_to_end] = Instruction::Jump(CodeAddress::new(end_pos));
178 }
179 }
180
181 fn generate_call_expression(&mut self, node: &Node) {
182 if let Node::CallExpression(expr) = node {
183 if let Node::MemberExpression(member) = &*expr.callee {
185 if let (Node::Identifier(obj_name), Node::Identifier(prop_name)) =
186 (&*member.object, &*member.property) {
187
188 if obj_name == "Math" {
190 let builtin_name = format!("Math.{}", prop_name);
191 for arg in &expr.arguments {
193 self.visit_node(arg);
194 }
195 self.instructions().push(Instruction::CallBuiltin(
197 builtin_name,
198 crate::vm::types::ArgIndex::new(expr.arguments.len())
199 ));
200 return;
201 }
202
203 if let Node::String(_) = &*member.object {
205 let builtin_name = format!("String.prototype.{}", prop_name);
206 self.visit_node(&*member.object);
208 for arg in &expr.arguments {
209 self.visit_node(arg);
210 }
211 self.instructions().push(Instruction::CallBuiltin(
213 builtin_name,
214 crate::vm::types::ArgIndex::new(expr.arguments.len() + 1)
215 ));
216 return;
217 }
218
219 if let Node::Identifier(obj_name) = &*member.object {
221 if self.is_array_variable(obj_name) && (prop_name == "push" || prop_name == "pop") {
222 let builtin_name = format!("Array.prototype.{}", prop_name);
223 self.visit_node(&*member.object);
225 for arg in &expr.arguments {
226 self.visit_node(arg);
227 }
228 self.instructions().push(Instruction::CallBuiltin(
230 builtin_name,
231 crate::vm::types::ArgIndex::new(expr.arguments.len() + 1)
232 ));
233 return;
234 }
235 }
236 }
237 }
238
239 for arg in &expr.arguments {
241 self.visit_node(arg);
242 }
243 self.visit_node(&expr.callee);
244 self.instructions()
245 .push(Instruction::Call(crate::vm::types::FunctionIndex::new(
246 expr.arguments.len(),
247 )));
248 }
249 }
250
251 fn generate_new_expression(&mut self, node: &Node) {
252 if let Node::NewExpression(expr) = node {
253 for arg in &expr.arguments {
254 self.visit_node(arg);
255 }
256 self.visit_node(&expr.callee);
257 self.instructions().push(Instruction::New);
258 }
259 }
260
261 fn generate_member_expression(&mut self, node: &Node) {
262 if let Node::MemberExpression(expr) = node {
263 self.visit_node(&expr.object);
264
265 match &*expr.property {
267 Node::Identifier(name) => {
268 let constant_id = <Self as crate::bytecode::scope::constants::ConstantManager>::add_constant(self, name.clone());
270 self.instructions().push(Instruction::PushConst(constant_id));
271 }
272 _ => {
273 self.visit_node(&expr.property);
275 }
276 }
277
278 self.instructions().push(Instruction::GetProperty);
279 }
280 }
281}